#!/usr/bin/python3
# -*- coding:utf-8 -*-

from qturboframe.lib.utils.by import By
from qturboframe.public_ui.h_ui.form import Form as HuiForm
from BladeFerm.Lib.Common import logger
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.public_ui.__common__ import deal_form_data
from BladeFerm.hui2_app.hui2_lib.input_type import InputType
from BladeFerm.hui2_app.hui2_lib.check import CheckSingle


class Form(HuiForm):
    '''
    form表单填入
    '''

    __CHECKBOX_SINGLE_CLASS = r'h-checkbox-wrapper'   # 单选框控件

    def button_option(self, text='查询'):
        '''
        操作表单中按钮。例如点击 查询、重置、更多、简单 等按钮
        :param text: 查询、重置、更多、简单
        :return:
        '''
        self.element.click()
        button_element = self.element.find_elements_by_attribute(
            By.CSS_SELECTOR, 'button.h-btn', 'text:' + text,
            timeout=1)
        if button_element:
            button_element[0].click()
            logger.info(f'点击按钮：{text} 完成')
            return True
        elif not button_element and text == '更多':
            button_element_2 = self.element.find_elements_by_attribute(
                By.CSS_SELECTOR, 'button.h-btn', 'text:简单', timeout=1)
            if button_element_2:
                logger.info(f'表单填充项已经展开')
            else:
                logger.warning(f'更多 按钮未找到！')
                return False
        elif not button_element and text == '简单':
            button_element_2 = self.element.find_elements_by_attribute(
                By.CSS_SELECTOR, 'button.h-btn', 'text:更多', timeout=1)
            if button_element_2:
                logger.info(f'表单填充项已经收起！')
            else:
                logger.warning(f'简单 按钮未找到！')
                return False
        else:
            SeleniumError(f'{text} 按钮未找到！')

    def auto_fill(self, inputdata):
        '''
        hui表单自动填充功能

        :Args:
            inputdata: 输入数据，需要定位的表单抬头和待输入文本
                input_data_key  :  输入格式支持2种。
                    1. 直接写key值；
                    2.key值后指定控件序号，'#'连接。如 'key#2'，表示第2个包含key的控件
                input_data_value:  输入格式支持3种。
                    1. 直接写value值；
                    2.value值后指定检查类型，'#'连接
                        - 'value#R': 表示检查value值输入控件是否只读类型
                        - 'value#D': 表示检查value值输入控件是否存在默认值
                        - 'value#M': 表示检查value值输入控件是否是必填项
                    3.多选框填写值时，用英文 逗号 分割。例如： '中信银行,上海银行'
                    4.日期填写格式：单个日期: '2022-05企业日志查询-18' 范围日期格式： '2022-05企业日志查询-18 - 2022-05企业日志查询-23' (中间的分割符号是：' - ')

        :Raises:
            SeleniumError: 表单填充或校验出错

        :Example:
         - 例: form.auto_fill({'姓名':'admin','年龄':'25','工号':'asdf1234'})
        '''
        logger.info("表单填写开始")
        try:
            for input_key, input_value in inputdata.items():
                if input_value == '':
                    continue

                key, value, flag, label_seq = deal_form_data(input_key, input_value)

                label_elements = self.element.find_elements_by_attribute(
                    'class name', 'h-form-item-label', 'text:' + key,
                    timeout=self.timeout)
                if len(label_elements) == 0:
                    raise SeleniumError("没有找到“{}”控件".format(key))
                label = label_elements[label_seq - 1]
                self.__foud_div_type(label, input_key, input_value)
                # 确定类型
                control_type_list = self.__confirm_type()
                if len(control_type_list) > 1:
                    templist = list()
                    for i in range(0, len(control_type_list)):
                        templist.append([value[i]])
                    value = templist
                elif len(control_type_list) == 0:
                    continue
                else:
                    value = [value]
                # 识别控件并执行
                for i, control_type in enumerate(control_type_list):
                    # 根据控件类型选择控件操作
                    if control_type == self.__INPUT_TYPE_CLASS:
                        self.__deal_input_type(key, value[i], flag)
                    elif control_type == self.__INPUT_NUMBER_CLASS:
                        self.__deal_input_number(key, value[i], flag)
                    elif control_type == self.__TYPE_FIELD_CLASS:
                        self.__deal_type_field(key, value[i], flag)
                    elif control_type == self.__SELECT_SINGLE_CLASS:
                        self.__deal_select_single(key, value[i], flag)
                    elif control_type == self.__SELECT_MULTIPLE_CLASS:
                        self.__deal_select_multiple(key, value[i], flag)
                    elif control_type == self.__SELECT_TREE_SINGLE_CLASS:
                        self.__deal_select_tree_single(key, value[i], flag)
                    elif control_type == self.__SELECT_TREE_MULTIPLE_CLASS:
                        self.__deal_select_tree_multiple(key, value[i], flag)
                    elif control_type == self.__SELECT_TABLE_SINGLE_CLASS:
                        self.__deal_select_table_single(key, value[i], flag)
                    elif control_type == self.__RADIO_CLASS:
                        self.__deal_radio(key, value[i], flag)
                    # elif control_type == self.__CHECKBOX_CLASS:
                    #     self.__deal_checkbox(key, value[i], flag)
                    elif control_type == self.__CHECKBOX_CLASS:
                        self.__deal_checkbox(key, value[i], flag)
                    elif control_type == self.__CALENDAR_CLASS:
                        i_icon = self._elements.find_element_by_attribute(
                            'css selector', 'div.h-date-picker-rel i.h-icon', timeout=self.timeout)
                        icon_class_list = i_icon.get_attribute('class').split(' ')
                        if 'h-icon-time' in icon_class_list:
                            self.__deal_timer(key, value[i], flag)
                        elif 'h-icon-activity' in icon_class_list:
                            self.__deal_calendar(key, value[i], flag)
        except Exception as msg:
            raise SeleniumError(str(msg))
        logger.info("表单填写结束")

    def __foud_div_type(self, dirver, input_key, input_value):
        '''
        # 找<div class="h-form-item-content"> 的下级div，根据class的值判断控件类型！  李吉凯 2022-05企业日志查询-18
        反洗钱系统 与公共的区别在于。下拉框，日期等控件与<div class="h-form-item-content">直接还嵌套了1个div。所以的单独重写，不可复用。
        :param dirver:
        :param input_key:
        :param input_value:
        :return:
        '''
        logger.info(f'{input_key}:{input_value} 查找控件类型元素！')
        ele = dirver.find_element_by_attribute(
                    'xpath', './following-sibling::div[@class=\'h-form-item-content\']/'
                             'div[not(contains(@style, "display: none;"))]', timeout=3)
        logger.debug(f'foud_div_type: {ele}')
        # 判断是否是控件类型的div，若不是找下层的div
        if 'display: flex;' != ele.get_attribute('style'):
            self._control_div = ele
        else:
            ele2 = ele.find_elements_by_attribute(By.CSS_SELECTOR, 'div>div', timeout=3)
            logger.debug(f'Second foud_div_type: {ele2}')
            if ele:
                self._control_div = ele2[0]
            else:
                raise SeleniumError(f'{input_key}:{input_value} 未找到控件类型元素！')

    def auto_fill_group(self, inputdata):
        '''
        hui表单自动填充功能

        :Args:
         - inputdata: 输入数据，需要定位的表单抬头和待输入文本
            - 场景类型: 客户信息异常
              证件地址长度: [True@inner, <, 20]
              地址长度: [True@inner, <, 30]

        :Raises:
            SeleniumError: 表单填充或校验出错

        :Example:
         - 例: form.auto_fill({'姓名':'admin','年龄':'25','工号':'asdf1234'})
        '''
        logger.info("表单填写开始")
        try:
            for input_key, input_value in inputdata.items():
                if input_value == '':  # 数值为空字符串，
                    continue

                if isinstance(input_value, str):
                    key, value, flag, label_seq = deal_form_data(input_key, input_value)
                    label_elements = self.element.find_elements_by_attribute(
                        'class name', 'h-form-item-label', 'text:' + key,
                        timeout=self.timeout)
                    if len(label_elements) == 0:
                        raise SeleniumError("没有找到“{}”控件".format(key))
                    label = label_elements[label_seq - 1]
                    self.__foud_div_type(label, key, value)
                    self.__fill_data(key, value, flag)
                elif isinstance(input_value, list):
                    key, value0, flag, label_seq = deal_form_data(input_key, input_value[0])
                    label_ele = self.element.find_element_by_attribute(
                        'class name', 'h-form-item-label', 'text:' + key,
                        timeout=self.timeout)
                    # div_row_element = None
                    div_row_eles = label_ele.find_elements_by_attribute('xpath',
                                                                      './/ancestor::div[contains(@class,"h-row")]',
                                                                        timeout=self.timeout)
                    if div_row_eles:
                        div_row_element = div_row_eles[0]
                        label_elements = div_row_element.find_elements_by_attribute(
                            'class name', 'h-form-item-label', timeout=self.timeout)
                        label_num = len(label_elements)
                        logger.info(f'found label element number: {label_num} ')
                        for i, unit in enumerate(input_value):
                            temp_lst = unit.split('@') if isinstance(unit, str) else [unit]
                            value, pos = (temp_lst[0], temp_lst[1]) if len(temp_lst) == 2 else (temp_lst[0], 'R')
                            if i < label_num:
                                cur_label_ele = label_elements[i]
                            else:
                                raise SeleniumError(f'数据的个数大于了输入控件的个数{label_num}，请检查！')
                            if pos == 'R':
                                # label元素后面判断控件对应的类型
                                self.__foud_div_type(cur_label_ele, key, value)
                            elif pos == 'L':
                                pass
                                # label元素前面判断控件对应的类型，暂无此种类型
                            else:
                                # label元素内部判断控件对应的类型
                                logger.info(f'{input_key}:{value} 查找控件类型元素！')
                                ele = cur_label_ele.find_element_by_attribute(
                                    By.CSS_SELECTOR, 'label', timeout=3)
                                logger.debug(f'foud_div_type: {ele}')
                                self._control_div = ele
                            self.__fill_data(key, value, flag)
                    else:
                        raise SeleniumError(f'没有找到{key}控件对应的行元素')
        except Exception as msg:
            raise SeleniumError(str(msg))
        logger.info("表单填写结束")

    def __confirm_type(self):
        # 获取控件层div的class属性
        div_class_list = self._control_div.get_attribute('class').split(' ')
        logger.debug(f'div_class_list: {div_class_list}')
        # 判定控件类型
        if self.__INPUT_TYPE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__INPUT_TYPE_CLASS]
        elif self.__INPUT_NUMBER_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__INPUT_NUMBER_CLASS]
        elif self.__TYPE_FIELD_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__TYPE_FIELD_CLASS]
        elif self.__SELECT_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_SINGLE_CLASS]
        elif self.__SELECT_MULTIPLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_MULTIPLE_CLASS]
        elif self.__SELECT_TREE_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_TREE_SINGLE_CLASS]
        elif self.__SELECT_TREE_MULTIPLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_TREE_MULTIPLE_CLASS]
        elif self.__SELECT_TABLE_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__SELECT_TABLE_SINGLE_CLASS]
        elif self.__CALENDAR_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__CALENDAR_CLASS]
        elif self.__RADIO_CLASS in div_class_list:
            self._elements = self._control_div.find_elements_by_attribute(
                'tag name', 'input', timeout=self.timeout)
            return [self.__RADIO_CLASS]
        elif self.__CHECKBOX_SINGLE_CLASS in div_class_list:
            self._elements = self._control_div
            return [self.__CHECKBOX_SINGLE_CLASS]
        elif self.__CHECKBOX_CLASS in div_class_list:
            self._elements = self._control_div.find_elements_by_attribute(
                'tag name', 'input', timeout=self.timeout)
            return [self.__CHECKBOX_CLASS]
        elif self.__GROUP_CLASS in div_class_list:
            templist = list()
            sub_divs = self._control_div.find_elements_by_attribute(
                'xpath', './div/div', timeout=self.timeout)
            for i in range(0, len(sub_divs)):
                self._control_div = sub_divs[i]
                templist.extend(self.__confirm_type())
            return templist
        else:
            logger.warn('非表单控件')
            return []

    def __fill_data(self, key, value, flag):

        # 确定类型
        control_type_list = self.__confirm_type()
        if len(control_type_list) > 1:
            templist = list()
            # todo: value 若是str而非字典，就会有问题哈。
            for i in range(0, len(control_type_list)):
                templist.append([value[i]])
            value = templist
        elif len(control_type_list) == 0:
            pass
        else:
            value = [value]
        # 识别控件并执行
        for i, control_type in enumerate(control_type_list):
            # 根据控件类型选择控件操作
            if control_type == self.__INPUT_TYPE_CLASS:
                self.__deal_input_type(key, value[i], flag)
            elif control_type == self.__INPUT_NUMBER_CLASS:
                self.__deal_input_number(key, value[i], flag)
            elif control_type == self.__TYPE_FIELD_CLASS:
                self.__deal_type_field(key, value[i], flag)
            elif control_type == self.__SELECT_SINGLE_CLASS:
                self.__deal_select_single(key, value[i], flag)
            elif control_type == self.__SELECT_MULTIPLE_CLASS:
                self.__deal_select_multiple(key, value[i], flag)
            elif control_type == self.__SELECT_TREE_SINGLE_CLASS:
                self.__deal_select_tree_single(key, value[i], flag)
            elif control_type == self.__SELECT_TREE_MULTIPLE_CLASS:
                self.__deal_select_tree_multiple(key, value[i], flag)
            elif control_type == self.__SELECT_TABLE_SINGLE_CLASS:
                self.__deal_select_table_single(key, value[i], flag)
            elif control_type == self.__RADIO_CLASS:
                self.__deal_radio(key, value[i], flag)
            elif control_type == self.__CHECKBOX_SINGLE_CLASS:
                self.__deal_checkbox_single(key, value[i], flag)
            elif control_type == self.__CHECKBOX_CLASS:
                self.__deal_checkbox(key, value[i], flag)
            elif control_type == self.__CALENDAR_CLASS:
                i_icon = self._elements.find_element_by_attribute(
                    'css selector', 'div.h-date-picker-rel i.h-icon', timeout=self.timeout)
                icon_class_list = i_icon.get_attribute('class').split(' ')
                if 'h-icon-time' in icon_class_list:
                    self.__deal_timer(key, value[i], flag)
                elif 'h-icon-activity' in icon_class_list:
                    self.__deal_calendar(key, value[i], flag)

    def __deal_input_type(self, key, value, flag=''):
        '''
        处理hui文本框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        input_type = InputType(self._elements, timeout=self.timeout)
        text = value  #
        if flag == '':
            logger.info(f'文本框填充，{key}:{text}')
            input_type.set_value(text)
            return
        else:
            if 'R' in flag:
                if input_type.is_readonly():
                    logger.info(key + '只读检查通过。')
                else:
                    raise SeleniumError(key + '只读检查未通过。')
            if 'D' in flag:
                if input_type.is_default(text):
                    logger.info(key + '默认值检查通过。')
                else:
                    raise SeleniumError(key + '默认值检查未通过。')
            if 'M' in flag:
                if input_type.is_nonnull():
                    logger.info(key + '必填项校验通过。')
                    input_type.set_value(text)
                else:
                    raise SeleniumError(key + '必填项校验未通过。')

    def __deal_checkbox_single(self, key, value, flag):
        logger.debug(f'self._elements: {self._elements}, {type(self._elements)}')
        check_div = CheckSingle(self._elements, timeout=self.timeout)
        if flag == '':
            check_div.set_status(value)
        else:
            if 'D' in flag:
                if check_div.is_default(value):
                    logger.info(key + '默认值检查通过。')
                else:
                    raise SeleniumError(key + '默认值检查未通过。')


